package snake;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Objects;
import java.util.Random;


class Node{//节点类
    private int x;//x坐标
    private int y;//y坐标

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
    public Node(int x,int y){this.x=x;this.y=y;}
    //画小方块
    private void drawRectangle(Graphics g){g.fillRect(x,y,20-1,20-1);}
    //画园
    private void drawOval(Graphics g){g.fillOval(x,y,20-1,20-1);}
    //绘制蛇的身体
    public void drawBody(Graphics g,int i){
        g.setColor(Color.YELLOW);
        if(0==i)drawOval(g);else drawRectangle(g);
    }
    //绘制食物
    public void drawFood(Graphics g){g.setColor(Color.CYAN); drawRectangle(g);}

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        Node node = (Node) object;
        return x == node.x && y == node.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}
public class snake extends Frame {
    public static final int Window_X=200;//窗体的位置x坐标
    public static final int Window_Y=200;//窗体位置y坐标
    public static final int Window_W=600;//窗体的大小,宽
    public static final int Window_H=500;//窗体大小，高
    //设置蛇的身体变量，并初始化3段，第一段为头
    private Node[] body={
            new Node(140,100),
            new Node(120,100),
            new Node(100,100)
    };
    private boolean isRunning=true;//程序是否还在运行
    public static final int SleepTime=500;//刷新时间
    //1上3下,0左2右
    private int direction=2;
    private Node food=new Node((new Random().nextInt(Window_W/20-1)*20),(new Random().nextInt(Window_H/20-3)*20));

    public snake(){
        //绘制窗体，初始化窗体
        this.setLocation(Window_X,Window_Y);//设置窗体初始位置
        this.setBackground(Color.LIGHT_GRAY);//设置窗体背景颜色
        this.setSize(Window_W,Window_H);//设置窗体大小
        this.setResizable(false);//设置窗体不可以更改大小
        //增加窗体关闭事件的监听
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);//如果关闭窗体，就推出程序
            }
        });
        //增加键盘事件监听
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int dir=e.getKeyCode();
                //1上3下,0左2右
                int dir_temp=-1;
                switch (dir){
                    case KeyEvent.VK_UP:dir_temp=1;break;
                    case KeyEvent.VK_DOWN:dir_temp=3;break;
                    case KeyEvent.VK_LEFT:dir_temp=0;break;
                    case KeyEvent.VK_RIGHT:dir_temp=2;break;
                }
                if(-1!=dir_temp && direction%2 != dir_temp%2)direction=dir_temp;
            }
        });
        this.setVisible(true);//设置窗体可见
        move();
    }
    //窗体发生改变时，重新绘制窗体时都会调用paint方法，重写paint方法
    @Override
    public void paint(Graphics g){
        //绘制蛇的身体
        for (int i=0;i<body.length;i++){
            body[i].drawBody(g,i);
        }
        //绘制食物
        food.drawFood(g);
        if(iseat()){
            Node[] temp=new Node[body.length+1];
            System.arraycopy(body,0,temp,1,body.length);
            temp[0]=getNewHead();
            body=temp;//身体变长
            createFood();//重新创建食物
        }
        if(gameOver()){
            g.setColor(Color.PINK);
            g.setFont(new Font("",Font.PLAIN,80));
            g.drawString("Game Over",60,300);
        }
    }
    //蛇的移动
    public void move(){
        while (isRunning){
            Node[] temp=new Node[body.length];
            System.arraycopy(body,0,temp,1,body.length-1);
            temp[0]=getNewHead();
            body=temp;
            try {
                Thread.sleep(SleepTime);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            this.repaint();//修改完坐标之后需要重绘，才能让蛇动起来
        }
    }
    private Node getNewHead(){
        Node NewNode=body[0];
        switch (direction){
            case 0:NewNode=new Node(NewNode.getX()-20,NewNode.getY());break;
            case 1:NewNode=new Node(NewNode.getX(),NewNode.getY()-20);break;
            case 2:NewNode=new Node(NewNode.getX()+20,NewNode.getY());break;
            case 3:NewNode=new Node(NewNode.getX(),NewNode.getY()+20);break;
        }
        return NewNode;
    }
    //生成食物
    public void createFood(){
        food=new Node(getRandomCoord(Window_W/20-1,0)*20,getRandomCoord(Window_H/20-1,3)*20);
    }
    private int getRandomCoord(int max,int min){
        return new Random().nextInt(max-min+1)+min;
    }
    //吃食物
    public boolean iseat(){
        Node NewHead=getNewHead();
        if(NewHead.equals(food)){
            //吃到食物
            return true;
        }
        return false;
    }
    //结束游戏，1.碰到边界；2.碰到身体
    public boolean gameOver(){
        //1.碰到边界
        if(body[0].getX()<20||body[0].getY()<40 || body[0].getX()>560 || body[0].getY()>=480){
            System.out.println("body-x:"+body[0].getX()+",body-y:"+body[0].getY());
            isRunning=false;
            return true;
        }
        //2.碰到自己的身体
        for (int i = 1; i < body.length; i++) {
            if(body[0].equals(body[i])){
                isRunning=false;
                return true;
            }
        }
        return false;
    }


    public static void main(String[] args) {
        new snake();
    }
}
